var $ = layui.$;
var editor;
var flows;
var codeMirrorInstances = {};
var socket;
var version = 'lastest';

function renderCodeMirror() {
    codeMirrorInstances = {};
    $('[codemirror]').each(function () {
        var $dom = $(this);
        if ($dom.attr("rendered") == 'true') {
            return;
        }
        $dom.attr("rendered", true)
        var cm = CodeMirror(this, {
            mode: 'spiderflow',	//语法
            theme: 'idea',	//设置样式
            placeholder: $dom.attr("placeholder"),
            value: $dom.attr('data-value') || '',
            scrollbarStyle: 'null',	//隐藏滚动条
        });
        initHint(cm);
        codeMirrorInstances[$(this).attr('codemirror')] = cm;
        cm.on('change', function () {
            $dom.attr('data-value', cm.getValue());
            if ($dom.attr('codemirror') == 'condition') {
                var $select = $('select[name="exception-flow"]');
                $select.siblings("div.layui-form-select").find('dl dd[lay-value=' + $select.val() + ']').click();
            }
            serializeForm();
        });
        codeMirrorInstances[$(this).attr('codemirror')] = cm;
    });
}

function getCellData(cellId, keys) {
    var cell = editor.getModel().getCell(cellId);
    var data = [];
    var object = cell.data.object;
    for (var k in keys) {
        var key = keys[k];
        if (Array.isArray(object[key])) {
            var array = object[key];
            for (var i = 0, len = array.length; i < len; i++) {
                data[i] = data[i] || {};
                data[i][key] = array[i];
            }
        }
    }
    return data;
}

function serializeForm() {
    var $container = $(".properties-container");
    var _version = $container.data('version');
    if (_version && _version != version) {
        return;
    }
    var cellId = $container.attr('data-cellid');
    var model = editor.getModel();
    var cell = model.getCell(cellId);
    if (!cell) {
        return;
    }
    var shape = cell.data.get('shape');
    cell.data.reset({});
    $.each($(".properties-container form").serializeArray(), function (index, item) {
        var name = item.name;
        var value = item.value;
        if ($(".properties-container form *[name=" + name + "].array").length > 0) {
            var array = cell.data.get(name) || [];
            array.push(value);
            cell.data.set(name, array);
        } else {
            if (name == 'value') {
                if (cell.getValue() != value) {
                    model.beginUpdate();
                    try {
                        cell.setValue(value);
                        model.execute(new mxValueChange(model, cell, value));
                    } finally {
                        model.endUpdate();
                    }
                }
            }
            if (name == 'lineWidth') {
                editor.graph.setCellStyles('strokeWidth', value, [cell]);
            }
            if (name == 'line-style') {
                editor.graph.setCellStyles('sharp', undefined, [cell]);
                editor.graph.setCellStyles('rounded', undefined, [cell]);
                editor.graph.setCellStyles('curved', undefined, [cell]);
                editor.graph.setCellStyles(value, 1, [cell]);
            }
            cell.data.set(name, value);
        }
    });
    $(".properties-container form [codemirror]").each(function () {
        var $dom = $(this);
        var name = $dom.attr('codemirror');
        var value = $dom.attr('data-value');
        if ($dom.hasClass("array")) {
            var array = cell.data.get(name) || [];
            array.push(value);
            cell.data.set(name, array);
        } else {
            cell.data.set(name, value);
        }
    });
    $(".properties-container form input[type=checkbox]").each(function () {
        if (this.value == 'transmit-variable') {
            if ($(this).is(":checked")) {
                editor.graph.setCellStyles('dashed', undefined, [cell]);
            } else {
                editor.graph.setCellStyles('dashed', 1, [cell]);
            }
        }
        cell.data.set(this.value, $(this).is(":checked") ? '1' : '0');
    });
    cell.data.set('shape', shape);
}

function resizeSlideBar() {
    var $dom = $(".sidebar-container");
    var height = $dom.height();
    var len = $dom.find("img").length;
    var totalHeight = len * 46;
    var w = Math.ceil(totalHeight / height);
    $dom.width(w * 50);
    $(".editor-container,.xml-container").css("left", w * 50 + "px");
}

function validXML(callback) {
    var cell = editor.valid();
    if (cell) {
        layui.layer.confirm("检测到有箭头未连接到节点上，是否处理？", {
            title: '异常处理',
            btn: ['处理', '忽略'],
        }, function (index) {
            layui.layer.close(index);
            editor.selectCell(cell);
        }, function () {
            callback && callback();
        })
    } else {
        callback && callback();
    }
}

$(function () {
    $.ajax({
        url: 'spider/other',
        type: 'post',
        data: {
            id: getQueryString('id')
        },
        dataType: 'json',
        success: function (others) {
            flows = others;
        }
    })
    $.ctrl = function (key, callback, args) {
        var isCtrl = false;
        $(document).keydown(function (e) {
            if (!args) args = [];
            if (e.keyCode == 17) isCtrl = true;
            if (e.keyCode == key.charCodeAt(0) && isCtrl) {
                callback.apply(this, args);
                isCtrl = false;
                return false;
            }
        }).keyup(function (e) {
            if (e.keyCode == 17) isCtrl = false;
        });
    };
    $.ctrl('S', function () {
        $('input,textarea').blur();
        Save();
    });
    $.ctrl('Q', function () {
        $('input,textarea').blur();
        $(".btn-test").click();
    });
    resizeSlideBar();
    var templateCache = {};

    function loadTemplate(cell, model, callback) {
        serializeForm();
        var cells = model.cells;
        var template = cell.data.get('shape') || 'root';
        if (cell.isEdge()) {
            template = 'edge';
        }
        var v = version;
        var render = function () {
            layui.laytpl(templateCache[template]).render({
                data: cell.data,
                value: cell.value,
                flows: flows || [],
                model: model,
                cell: cell
            }, function (html) {
                $(".properties-container").attr('data-version', v).html(html).attr('data-cellid', cell.id);
                layui.form.render();
                renderCodeMirror();
                resizeSlideBar();
                callback && callback();
            })
        }
        if (templateCache[template]) {
            render();
            return;
        }
        $.ajax({
            url: 'resources/templates/' + template + ".html",
            async: false,
            success: function (content) {
                templateCache[template] = content;
                render();
            }
        });
    }

    if (!mxClient.isBrowserSupported()) {
        layui.layer.msg('浏览器不支持!!');
    } else {
        editor = new SpiderEditor({
            element: $('.editor-container')[0],
            selectedCellListener: function (cell) {	//选中节点后打开属性面板
                loadTemplate(cell, editor.getModel(), serializeForm);
            }
        });
        //绑定工具条点击事件
        bindToolbarClickAction(editor);
        //加载图形
        loadShapes(editor, $('.sidebar-container')[0]);
        layui.form.on('checkbox', function (e) {
            serializeForm();
        });
        layui.table.on('tool', function (obj) {
            layui.layer.confirm('您确定要删除吗？', {
                title: '删除'
            }, function (index) {
                obj.del();
                serializeForm();
                renderCodeMirror();
                layui.layer.close(index);
            });
        })
        //节点名称输入框事件
        $("body").on("mousewheel", ".layui-tab .layui-tab-title", function (e, delta) {
            var $dom = $(this);
            var wheel = e.originalEvent.wheelDelta || -e.originalEvent.detail;
            var delta = Math.max(-1, Math.min(1, wheel));
            e.preventDefault = function () {
            }
            if (delta > 0) {
                $dom.scrollLeft($dom.scrollLeft() - 60);
            } else {
                $dom.scrollLeft($dom.scrollLeft() + 60);
            }
            return false;
        }).on("dblclick", ".layui-input-block[codemirror]", function () {
            if ($(this).parent().hasClass("layui-layer-content")) {
                return;
            }
            var tag = $(this).prev().html();
            if (tag == undefined || tag == 'undefined') {
                tag = '';
            }
            layui.layer.open({
                type: 1,
                title: '请输入' + tag + '表达式',
                content: $(this),
                skin: 'codemirror',
                area: ['800px', '400px']
            })
        }).on("blur", "input,textarea", function () {
            serializeForm();
        }).on("click", ".history-version li", function () {
            var timestamp = $(this).data("timestamp");
            layui.layer.confirm('你确定要恢复到该版本吗？', function (index) {
                layui.layer.close(index);
                var layerIndex = layui.layer.load(1);
                $.ajax({
                    url: 'spider/history',
                    data: {
                        id: id,
                        timestamp: timestamp
                    },
                    success: function (data) {
                        if (data.code == 1) {
                            version = timestamp;
                            editor.setXML(data.data);
                            layui.layer.close(layerIndex);
                            layui.layer.msg('恢复成功')
                        } else {
                            layui.layer.msg(data.message);
                        }
                    }
                })
            });
        }).on("click", ".btn-history", function () {
            $.ajax({
                url: 'spider/history',
                data: {
                    id: id
                },
                success: function (data) {
                    if (data.code == 1) {
                        if (data.data.length > 0) {
                            var array = [];
                            for (var i = data.data.length - 1; i >= 0; i--) {
                                var timestamp = Number(data.data[i])
                                array.push({
                                    time: new Date(timestamp).format('yyyy-MM-dd hh:mm:ss'),
                                    timestamp: timestamp
                                })
                            }
                            layui.laytpl($('#history-version-tmpl').html()).render(array, function (html) {
                                layui.layer.open({
                                    type: 1,
                                    title: '历史版本',
                                    id: 'history-revert',
                                    shade: 0,
                                    resize: false,
                                    content: html,
                                    offset: 'rt'
                                })
                            })
                        } else {
                            layui.layer.msg('暂无历史版本！');
                        }
                    } else {
                        layui.layer.msg(data.message);
                    }
                }
            })
        }).on("click", ".table-row-add", function () {	//添加一行
            serializeForm();
            var tableId = $(this).attr('for');
            var $table = $('#' + tableId);
            var cellId = $table.data('cell');
            var data = getCellData(cellId, $table.data('keys').split(","));
            data.push({});
            layui.table.reload(tableId, {
                data: data
            });
            renderCodeMirror();
        }).on("click", ".table-row-up", function () {	//上移
            var current = $(this).parent().parent().parent(); //获取当前<tr>
            var prev = current.prev();  //获取当前<tr>前一个元素
            if (current.index() > 0) {
                current.insertBefore(prev); //插入到当前<tr>前一个元素前
                serializeForm();
            }
            renderCodeMirror();
        }).on("click", ".table-row-down", function () {	//下移
            var current = $(this).parent().parent().parent(); //获取当前<tr>
            var next = current.next(); //获取当前<tr>后面一个元素
            if (next) {
                current.insertAfter(next);  //插入到当前<tr>后面一个元素后面
                serializeForm();
            }
            renderCodeMirror();
        }).on("click", ".editor-form-node .function-remove,.editor-form-node .cmd-remove", function () {
            var $dom = $(this).parents(".draggable");
            $dom.remove();
            serializeForm();
        }).on("click", ".editor-form-node .cookie-batch", function () {
            var tableId = $(this).attr('for');
            var $table = $('#' + tableId);
            var cellId = $table.data('cell');
            var data = getCellData(cellId, $table.data('keys').split(","));
            layui.layer.open({
                type: 1,
                title: '请输入Cookie',
                content: `<textarea id="cookies" name="cookies" placeholder="请输入Cookies，分号( ; )分隔Cookie，等于号( = )分隔name和value" autocomplete="off" class="layui-textarea"  lay-verify="required" style="height:250px"></textarea>`,
                area: '800px',
                btn: ['关闭', '设置'],
                btn2: function () {
                    var cookieStr = $("#cookies").val();
                    var cookieArr = cookieStr.split(";");
                    var length = $(".draggable").length;
                    serializeForm();
                    for (var i = 0; i < cookieArr.length; i++) {
                        var cookieItem = cookieArr[i];
                        var index = cookieItem.indexOf("=");
                        if (index < 0) {
                            layer.alert('cookie数据格式错误');
                            appendFlag = false;
                            return;
                        } else {
                            data.push({
                                'cookie-name': $.trim(cookieItem.substring(0, index)),
                                'cookie-value': $.trim(cookieItem.substring(index + 1))
                            })
                        }
                    }
                    layui.table.reload(tableId, {
                        data: data
                    });
                    renderCodeMirror();
                    serializeForm();
                }
            })
        }).on("click", ".editor-form-node .header-batch", function () {
            var tableId = $(this).attr('for');
            var $table = $('#' + tableId);
            var cellId = $table.data('cell');
            var data = getCellData(cellId, $table.data('keys').split(","));
            layui.layer.open({
                type: 1,
                title: '请输入Header',
                content: `<textarea id="headers" name="headers" placeholder="请输入Headers，一行一个，冒号( : )分割name和value" autocomplete="off" class="layui-textarea"  lay-verify="required" style="height:250px"></textarea>`,
                area: '800px',
                btn: ['关闭', '设置'],
                btn2: function () {
                    var headerStr = $("#headers").val();
                    var headerArr = headerStr.split("\n");
                    var length = $(".draggable").length;
                    for (var i = 0; i < headerArr.length; i++) {
                        var headerItem = headerArr[i];
                        var index = headerItem.indexOf(":");
                        if (index < 0) {
                            layer.alert('header数据格式错误');
                            return;
                        } else {
                            data.push({
                                'header-name': $.trim(headerItem.substring(0, index)),
                                'header-value': $.trim(headerItem.substring(index + 1))
                            })
                        }
                    }
                    layui.table.reload(tableId, {
                        data: data
                    });
                    renderCodeMirror();
                    serializeForm();
                }
            })
        }).on("click", ".editor-form-node .parameter-batch", function () {
            var tableId = $(this).attr('for');
            var $table = $('#' + tableId);
            var cellId = $table.data('cell');
            var data = getCellData(cellId, $table.data('keys').split(","));
            layui.layer.open({
                type: 1,
                title: '请输入参数',
                content: `<textarea id="paramters" name="paramters" placeholder="请输入参数，一行一个，冒号( : )、等号（ = ）、空格（  ）或tab（ \t ）分割name和value" autocomplete="off" class="layui-textarea"  lay-verify="required" style="height:250px"></textarea>`,
                area: '800px',
                btn: ['关闭', '设置'],
                btn2: function () {
                    var paramterStr = $("#paramters").val();
                    var paramterArr = paramterStr.split("\n");
                    var length = $(".draggable").length;
                    for (var i = 0; i < paramterArr.length; i++) {
                        var paramterItem = paramterArr[i];
                        var index = -1;
                        var indexArr = [];
                        indexArr.push(paramterItem.indexOf(":"));
                        indexArr.push(paramterItem.indexOf("="));
                        indexArr.push(paramterItem.indexOf(" "));
                        indexArr.push(paramterItem.indexOf("\t"));
                        for (var j = 0; j < indexArr.length; j++) {
                            if (indexArr[j] >= 0) {
                                if (index < 0) {
                                    index = indexArr[j];
                                }
                                index = Math.min(index, indexArr[j]);
                            }
                        }
                        if (index < 0) {
                            layer.alert('参数数据格式错误');
                            return;
                        } else {
                            data.push({
                                'parameter-name': $.trim(paramterItem.substring(0, index)),
                                'parameter-value': $.trim(paramterItem.substring(index + 1))
                            })
                        }
                    }
                    layui.table.reload(tableId, {
                        data: data
                    });
                    renderCodeMirror();
                    serializeForm();
                }
            })
        }).on("click", ".editor-form-node .function-add", function () {
            var index = $(".draggable").length;
            $(this).parent().parent().before('<div id="function' + index + '" class="draggable" draggable="true" ondragstart="drag(event)" ondrop="drop(event)" ondragover="allowDrop(event)"><div class="layui-form-item layui-form-relative"><i class="layui-icon layui-icon-close function-remove"></i><label class="layui-form-label">执行函数</label><div class="layui-input-block array" codemirror="function" placeholder="执行函数"></div></div></div>');
            renderCodeMirror();
        }).on("click", ".editor-form-node .cmd-add", function () {
            var index = $(".draggable").length;
            $(this).parent().parent().before('<div id="' + index + '" class="draggable" draggable="true" ondragstart="drag(event)" ondrop="drop(event)" ondragover="allowDrop(event)"><div class="layui-form-item layui-form-relative"><i class="layui-icon layui-icon-close cmd-remove"></i><label class="layui-form-label">执行命令</label><div class="layui-input-block array" codemirror="cmd" placeholder="执行命令"></div></div></div>');
            renderCodeMirror();
        });
        layui.form.on('select(bodyType)', function (e) {
            var bodyType = $(e.elem).val();
            $(".form-body-raw,.form-body-form-data").hide();
            if (bodyType == 'raw') {
                $(".form-body-raw").show();
            }
            if (bodyType == 'form-data') {
                $(".form-body-form-data").show();
            }
            renderCodeMirror();
            serializeForm();
        });
        layui.form.on('select(targetCheck)', function (data) {
            var targetDiv = $(data.elem).attr('target-div');
            var targetValue = $(data.elem).attr('target-value');
            if (targetDiv != null) {
                if (data.elem.value == targetValue) {
                    $("." + targetDiv).show();
                } else {
                    $("." + targetDiv).hide();
                }
            }
        });

        layui.form.on('checkbox(targetCheck)', function (data) {
            var targetDiv = $(data.elem).attr('target-div');
            if (targetDiv != null) {
                if (data.elem.checked) {
                    $("." + targetDiv).show();
                } else {
                    $("." + targetDiv).hide();
                }
            }
        });
        layui.element.on('tab', function () {
            for (var key in codeMirrorInstances) {
                codeMirrorInstances[key].refresh();
            }
        })
        layui.form.on('select', serializeForm);
        var id = getQueryString('id');
        if (id != null) {
            $.ajax({
                url: 'spider/xml',
                async: false,
                data: {
                    id: id
                },
                success: function (xml) {
                    editor.setXML(xml);
                }
            })
            //editor.importFromUrl('spider/xml?id=' +  id);
        }
        editor.onSelectedCell();
    }

    /**
     * 加载各种图形
     */
    function loadShapes(editor, container) {
        //定义图形
        var shapes = [{
            name: 'start',
            title: '开始',
            image: '',
            hidden: true,
            defaultAdd: true
        }, {
            name: 'request',
            image: '',
            title: '开始抓取',
            desc: '抓取静态HTML页面或者API接口，抓取结果存为resp变量中。<br/>支持方法参考命令提示。'
        }, {
            name: 'variable',
            image: '',
            title: '定义变量',
            desc: '定义流程变量。<br/>定义变量有先后顺序，先定义变量后续可以使用，拖动可以交换变量顺序。'
        }, {
            name: 'loop',
            image: '',
            title: '循环',
            desc: ''
        }, {
            name: 'forkJoin',
            image: '',
            title: '执行结束',
            desc: ''
        }, {
            name: 'comment',
            image: '',
            title: '注释',
            desc: '仅仅是注释,毫无作用'
        }, {
            name: 'output',
            image: '',
            title: '输出',
            desc: '输出流程中的变量结果（仅测试下有用）'
        }, {
            name: 'executeSql',
            image: '',
            title: '执行SQL',
            desc: '执行sql，需配置数据源，sql执行结果存于变量rs中。<br/>语句类型为：select，返回:List&lt;Map&lt;String,Object&gt;&gt;<br/>语句类型为：selectOne，返回:Map&lt;String,Object&gt;<br/>语句类型为：selectInt，返回:Integer<br/>语句类型为：insert、update、delete，返回:int，批量操作返回int数组<br/>sql中变量必须用 # # 包裹，如：#${title}#'
        }, {
            name: 'function',
            image: '',
            title: '执行函数',
            desc: '单独执行函数方法，结果不保存为变量'
        }, {
            name: 'process',
            image: '',
            title: '子流程',
            desc: '执行其他spiderFlow流程，父子流程变量共享'
        }];
        var addShape = function (shape) {
            var image = new Image();
            image.src = shape.image;
            image.title = shape.title;
            image.id = shape.name;
            image.onclick = function (ev) {
                if (shape.desc) {
                    layer.tips("(" + shape.name + ")" + shape.title + "<hr/>" + shape.desc, '#' + shape.name, {
                        tips: [1, '#3595CC'],
                        area: ['auto', 'auto'],
                        time: 4000
                    });
                }
            }
            if (!shape.hidden) {
                container.appendChild(image);
            }

            if (!shape.disabled) {
                editor.addShape(shape.name, shape.title || 'Label', image, shape.defaultAdd);
            }
        }
        for (var i = 0, len = shapes.length; i < len; i++) {
            addShape(shapes[i]);
        }
        $.ajax({
            url: 'spider/shapes',
            type: 'post',
            dataType: 'json',
            async: false,
            success: function (shapeExts) {
                for (var i = 0, len = shapeExts.length; i < len; i++) {
                    var shape = shapeExts[i];
                    addShape(shape);
                    var image = new Image();
                    image.src = shape.image;
                    image.title = shape.title;
                    editor.addShape(shape.name, shape.title || 'Label', image, false);
                    resizeSlideBar();
                }
            }
        })
    }
});

/**
 * 绑定工具条点击事件
 */
function bindToolbarClickAction(editor) {
    $(".xml-container textarea").bind('input propertychange', function () {
        editor.setXML($(this).val());
        editor.onSelectedCell();
    })
    $(".toolbar-container").on('click', '.btn-delete', function () {
        editor.deleteSelectCells();
    }).on("click", ".btn-selectAll", function () {
        editor.execute('selectAll');
    }).on('click', ".btn-undo", function () {
        editor.execute('undo');
    }).on('click', ".btn-redo", function () {
        editor.execute('redo');
    }).on('click', ".btn-cut", function () {
        editor.execute('cut');
    }).on('click', ".btn-copy", function () {
        editor.execute('copy');
    }).on('click', ".btn-paste", function () {
        editor.execute('paste');
    }).on('click', ".btn-console-xml", function () {
        console.log(editor.getXML());
    }).on('click', ".btn-edit-xml", function () {
        $(".editor-container").hide();
        $(".xml-container textarea").val(editor.getXML());
        $(".xml-container").show();
        $(this).removeClass('btn-edit-xml').addClass('btn-graphical-xml');
    }).on('click', ".btn-graphical-xml", function () {
        $(".editor-container").show();
        $(".xml-container").hide();
        $(this).removeClass('btn-graphical-xml').addClass('btn-edit-xml');
//		editor.setXML($(".xml-container textarea").val());
//		editor.onSelectedCell();
    }).on('click', '.btn-stop:not(.disabled)', function () {
        socket.send(JSON.stringify({
            eventType: 'stop'
        }));
    }).on('click', '.btn-resume:not(.disabled)', function () {
        $(this).addClass('disabled')
        $(".spiderflow-debug-tooltip").remove();
        socket.send(JSON.stringify({
            eventType: 'resume'
        }));
    }).on('click', '.btn-test', function () {
        runSpider(false);
    }).on('click', '.btn-debug', function () {
        runSpider(true);
    }).on('click', ".btn-return", function () {
        parent.openTab('爬虫列表', 'welcome', 'spiderList.html')
    }).on('click', ".btn-return-magic", function () {
        goUrl('爬虫列表', 'welcome', 'spiderListMagic.html')
    }).on('click', '.btn-save', function () {
        Save();
    }).on('click', '.btn-dock-right', function () {
        $('.main-container').addClass('right');
        $('.main-container .properties-container').width('40%');
        $('.main-container .resize-container').attr('style', 'top:0px;left:auto;');
        layui.table.resize('spider-variable');
        var resize = $('.resize-container')[0]
        resize.onmousedown = function (e) {
            var startX = e.clientX;
            resize.left = resize.offsetLeft;
            var box = $("body")[0];
            document.onmousemove = function (e) {
                layui.table.resize('spider-variable');
                var endX = e.clientX;
                var moveLen = resize.left + (endX - startX);
                var maxT = box.clientWidth - resize.offsetWidth;
                if (moveLen < 150) moveLen = 150;
                if (moveLen > maxT - 150) moveLen = maxT - 150;
                if (box.clientWidth - moveLen < 400 || box.clientWidth - moveLen > 800) {
                    return;
                }
                resize.style.left = moveLen + 'px';
                $(".editor-container").css('right', ($('body').width() - moveLen) + 'px')
                $(".properties-container").width(box.clientWidth - moveLen - 5);
                $(".xml-container").width($(".main-container").width() - $(".properties-container").width() - $(".sidebar-container").width() + 8);
            }
            document.onmouseup = function (evt) {
                document.onmousemove = null;
                document.onmouseup = null;
                resize.releaseCapture && resize.releaseCapture();
            }
            resize.setCapture && resize.setCapture();
            return false;
        }
    }).on('click', '.btn-dock-bottom', function () {
        resizeSlideBar();
        $('.main-container').removeClass('right');
        $('.properties-container').height(200).width('100%');
        $('.sidebar-container').css('bottom', '200px');
        $('.editor-container').css('bottom', '200px');
        $('.main-container .resize-container').attr('style', 'left:0px;top:auto;bottom:190px');
        var resize = $('.resize-container')[0]
        resize.onmousedown = function (e) {
            var startY = e.clientY;
            resize.top = resize.offsetTop;
            var box = $("body")[0];
            var maxT = box.clientHeight;
            document.onmousemove = function (e) {
                var moveLen = e.clientY;
                if (moveLen < 250) moveLen = 250;
                if (moveLen > maxT - 150) moveLen = maxT - 150;
                resize.style.top = moveLen + 'px';
                resizeSlideBar();
                $(".editor-container,.sidebar-container,.xml-container").css('bottom', ($('body').height() - moveLen) + 'px');
                $(".properties-container").height(box.clientHeight - moveLen - 5);
            }
            document.onmouseup = function (evt) {
                document.onmousemove = null;
                document.onmouseup = null;
                resize.releaseCapture && resize.releaseCapture();
            }
            resize.setCapture && resize.setCapture();
            return false;
        }
    })
    $('.btn-dock-bottom').click();
}

function runSpider(debug) {
    validXML(function () {
        $(".btn-debug,.btn-test,.btn-resume").addClass('disabled');
        $(".btn-stop").removeClass('disabled');
        var LogViewer;
        var tableMap = {};
        var first = true;
        var filterText = '';
        var testWindowIndex = layui.layer.open({
            id: 'test-window',
            type: 1,
            skin: 'layer-test',
            content: '<div class="test-window-container"><div class="output-container"><div class="layui-tab layui-tab-fixed layui-tab-brief"><ul class="layui-tab-title"></ul><div class="layui-tab-content"></div></div></div><canvas class="log-container" width="677" height="100"></canvas></div>',
            area: ["680px", "400px"],
            shade: 0,
            offset: 'rt',
            maxmin: true,
            maxWidth: 700,
            maxHeight: 400,
            title: '测试窗口',
            btn: ['关闭', '显示/隐藏输出', '显示/隐藏日志', '停止'],
            btn2: function () {
                var $output = $(".test-window-container .output-container");
                var $log = $(".test-window-container .log-container");
                if ($output.is(":hidden")) {
                    $output.show();
                    $output.find("canvas").each(function () {
                        if ($log.is(":hidden")) {
                            this.height = 290;
                        } else {
                            this.height = 200;
                        }
                    })
                    $log.attr('height', 100)
                    LogViewer.resize();
                    for (var tableId in tableMap) {
                        tableMap[tableId].instance.resize();
                    }
                } else {
                    $output.hide();
                    $log.attr('height', 320);
                    LogViewer.resize();
                    for (var tableId in tableMap) {
                        tableMap[tableId].instance.resize();
                    }
                }
                return false;
            },
            btn3: function () {
                var $output = $(".test-window-container .output-container");
                var $log = $(".test-window-container .log-container");
                if ($log.is(":hidden")) {
                    $log.show();
                    $log.attr('height', $output.is(":hidden") ? 320 : 100)
                    $output.find("canvas").each(function () {
                        this.height = 200;
                    });
                    LogViewer.resize();
                    for (var tableId in tableMap) {
                        tableMap[tableId].instance.resize();
                    }
                } else {
                    $log.hide();
                    $output.find("canvas").each(function () {
                        this.height = 320;
                    });
                    LogViewer.resize();
                    for (var tableId in tableMap) {
                        tableMap[tableId].instance.resize();
                    }
                }
                return false;
            },
            btn4: function () {
                var $btn = $("#layui-layer" + testWindowIndex).find('.layui-layer-btn3');
                if ($btn.html() == '停止') {
                    socket.send(JSON.stringify({
                        eventType: 'stop'
                    }));
                } else {
                    $(".btn-debug,.btn-test,.btn-resume").addClass('disabled');
                    $(".btn-stop").removeClass('disabled');
                    socket.send(JSON.stringify({
                        eventType: debug ? 'debug' : 'test',
                        message: editor.getXML()
                    }));
                    $btn.html('停止');
                }
                return false;
            },
            end: function () {
                if (socket) {
                    socket.close();
                    $(".spiderflow-debug-tooltip").remove();
                    $(".btn-stop,.btn-resume").addClass('disabled');
                    $(".btn-test,.btn-debug").removeClass('disabled')
                }
                if (LogViewer) {
                    LogViewer.destory();
                }
                for (var tableId in tableMap) {
                    tableMap[tableId].instance.destory();
                }
            },
            success: function (layero, index) {
                var logElement = $(".test-window-container .log-container")[0];
                var colors = {
                    'array': '#2a00ff',
                    'object': '#2a00ff',
                    'boolean': '#600100',
                    'number': '#000E59'
                }
                LogViewer = new CanvasViewer({
                    element: logElement,
                    onClick: function (e) {
                        onCanvasViewerClick(e, '日志');
                    }
                });
                $(layero).find(".layui-layer-btn")
                    .append('<div class="layui-inline"><input type="text" class="layui-input" placeholder="输入关键字过滤日志"/></div>')
                    .on("keyup", "input", function () {
                        LogViewer.filter(this.value);
                    });
                socket = createWebSocket({
                    onopen: function () {
                        socket.send(JSON.stringify({
                            eventType: debug ? 'debug' : 'test',
                            message: editor.getXML()
                        }));
                    },
                    onmessage: function (e) {
                        var event = JSON.parse(e.data);
                        var eventType = event.eventType;
                        var message = event.message;
                        if (eventType == 'finish') {
                            $(".spiderflow-debug-tooltip").remove();
                            $("#layui-layer" + testWindowIndex).find('.layui-layer-btn3').html('重新开始');
                            $(".btn-stop,.btn-resume").addClass('disabled');
                            $(".btn-test,.btn-debug").removeClass('disabled')
                        } else if (eventType == 'output') {
                            var tableId = 'output-' + message.nodeId;
                            var $table = $('#' + tableId);
                            if ($table.length == 0) {
                                tableMap[tableId] = {
                                    index: 0
                                };
                                var $tab = $(".test-window-container .output-container .layui-tab")
                                var outputTitle = '输出-' + tableId;
                                var cell = editor.getModel().cells[message.nodeId];
                                if (cell) {
                                    outputTitle = cell.value;
                                }
                                if (first) {
                                    $tab.find(".layui-tab-title").append('<li  class="layui-this">' + outputTitle + '</li>');
                                    $tab.find(".layui-tab-content").append('<div class="layui-tab-item layui-show" data-output="' + tableId + '"></div>');
                                    first = false;
                                } else {
                                    $tab.find(".layui-tab-title").append('<li>' + outputTitle + '</li>');
                                    $tab.find(".layui-tab-content").append('<div class="layui-tab-item" data-output="' + tableId + '"></div>');
                                }
                                $table = $('<canvas width="677" height="200"/>').appendTo($(".test-window-container .output-container .layui-tab-item[data-output=" + tableId + "]"));
                                $table.attr('id', tableId);
                                tableMap[tableId].instance = new CanvasViewer({
                                    element: document.getElementById(tableId),
                                    grid: true,
                                    header: true,
                                    style: {
                                        font: 'bold 13px Consolas'
                                    },
                                    onClick: function (e) {
                                        onCanvasViewerClick(e, '表格');
                                    }
                                })
                                var cols = [];
                                var texts = [new CanvasText({
                                    text: '序号',
                                    maxWidth: 100
                                })];
                                for (var i = 0, len = message.outputNames.length; i < len; i++) {
                                    texts.push(new CanvasText({
                                        text: message.outputNames[i],
                                        maxWidth: 200,
                                        click: true
                                    }));
                                }
                                tableMap[tableId].instance.append(texts);
                            }
                            var texts = [new CanvasText({
                                text: ++tableMap[tableId].index,
                                maxWidth: 200,
                                click: true
                            })];
                            for (var i = 0, len = message.outputNames.length; i < len; i++) {
                                var displayText = message.values[i];
                                var variableType = 'string';
                                if (Array.isArray(displayText)) {
                                    variableType = 'array';
                                    displayText = JSON.stringify(displayText);
                                } else {
                                    variableType = typeof displayText;
                                    if (variableType == 'object') {
                                        displayText = JSON.stringify(displayText);
                                    }
                                }
                                texts.push(new CanvasText({
                                    text: displayText,
                                    maxWidth: 200,
                                    color: colors[variableType] || 'black',
                                    click: true
                                }));
                            }
                            tableMap[tableId].instance.append(texts);
                            tableMap[tableId].instance.scrollTo(-1);
                        } else if (eventType == 'log') {
                            var texts = [];
                            var defaultColor = message.level == 'error' ? 'red' : '';
                            texts.push(new CanvasText({
                                text: message.level,
                                color: defaultColor
                            }));
                            texts.push(new CanvasText({
                                text: event.timestamp,
                                color: defaultColor
                            }));
                            var temp = message.message.split("{}");
                            message.variables = message.variables || [];
                            for (var i = 0, len = temp.length; i < len; i++) {
                                if (temp[i] != '') {
                                    texts.push(new CanvasText({
                                        text: temp[i],
                                        color: defaultColor
                                    }))
                                }
                                var object = message.variables[i];
                                if (object != undefined) {
                                    var variableType = '';
                                    var displayText = object;
                                    if (Array.isArray(object)) {
                                        variableType = 'array';
                                        displayText = JSON.stringify(displayText);
                                    } else {
                                        variableType = typeof object;
                                        if (variableType == 'object') {
                                            displayText = JSON.stringify(displayText);
                                        }
                                    }
                                    texts.push(new CanvasText({
                                        text: displayText,
                                        maxWidth: 330,
                                        color: colors[variableType] || '#025900',
                                        click: true
                                    }))
                                }
                            }
                            LogViewer.append(texts);
                            LogViewer.scrollTo(-1);
                        } else if (eventType == 'debug') {
                            $(".btn-resume").removeClass('disabled');
                            var type = message.event;
                            editor.selectCell(editor.graph.model.cells[message.nodeId]);
                            var selector;
                            if (type == 'request-parameter') {
                                $('.layui-tab-title li:eq(1)').click();
                            }
                            if (type == 'request-cookie') {
                                $('.layui-tab-title li:eq(2)').click();
                            }
                            if (type == 'request-header') {
                                $('.layui-tab-title li:eq(3)').click();
                            }
                            if (type == 'request-body') {
                                $('.layui-tab-title li:eq(4)').click();
                            }
                            if (type == 'common' || type == 'request-parameter' || type == 'request-header' || type == 'request-cookie') {
                                selector = '.layui-table-cell input[value=' + message.key + ']';
                            }
                            if ($(selector).length == 0) {
                                selector = '.properties-container input[name=' + message.key + ']';
                            }
                            if ($(selector).length == 0) {
                                selector = '.properties-container [codemirror=' + message.key + ']';
                            }
                            var o1 = $(selector).offset();
                            var $parent = $(".properties-container");
                            var o2 = $parent.offset();
                            if (o1.top > o2.top + $parent.height()) {
                                $parent[0].scrollTop = o1.top - o2.top;
                            }
                            var msg = message.value;
                            var isJson = Array.isArray(msg) || typeof msg == 'object';
                            if (!isJson) {
                                var temp = document.createElement("div");
                                (temp.textContent != null) ? (temp.textContent = msg) : (temp.innerText = msg);
                                msg = temp.innerHTML;
                                temp = null;
                            }
                            var content = '<div class="message-content" style="padding:10px;' + (isJson ? '' : 'font-weight: bold;font-family:Consolas;font-size:12px;') + '">' + (isJson ? '' : msg.replace(/\n/g, '<br>')).replace(/ /g, '&nbsp;').replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;') + '</div>';
                            var tooltip = bindTooltip(content, selector);
                            if (isJson) {
                                var $dom = $(tooltip.dom).find(".message-content");
                                jsonTree.create(msg, $dom[0]);
                            }
                        }
                    }
                });
            }
        })
    });
}

function bindTooltip(content, selector) {
    var dom = document.createElement('div');
    var $target = $(selector);
    var offset = $target.offset();
    dom.className = 'spiderflow-debug-tooltip';
    dom.style.bottom = ($("body").height() - offset.top) + 'px';
    dom.style.left = (offset.left + $target.width() / 2) + 'px';
    dom.innerHTML = '<div class="content">' + content + '</div>';
    document.body.appendChild(dom);
    $(selector).offset();
    return {
        dom: dom,
        close: function () {
            document.body.removeChild(dom);
        }
    }

}

//最近点击打开的弹窗
var index;

function onCanvasViewerClick(e, source) {
    var msg = e.text;
    var json;
    try {
        json = JSON.parse(msg);
        if (!(Array.isArray(json) || typeof json == 'object')) {
            json = null;
        }
    } catch (e) {

    }
    if (!json) {
        var temp = document.createElement("div");
        (temp.textContent != null) ? (temp.textContent = msg) : (temp.innerText = msg);
        msg = temp.innerHTML;
        temp = null;
    }
    layer.close(index);
    index = layer.open({
        type: 1,
        title: source + '内容',
        content: '<div class="message-content" style="padding:10px;' + (json ? '' : 'font-weight: bold;font-family:Consolas;font-size:12px;') + '">' + (json ? '' : msg.replace(/\n/g, '<br>')).replace(/ /g, '&nbsp;').replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;') + '</div>',
        shade: 0,
        area: json ? ['700px', '500px'] : 'auto',
        maxmin: true,
        maxWidth: (json ? undefined : 700),
        maxHeight: (json ? undefined : 400),
        success: function (dom, index) {
            var $dom = $(dom).find(".message-content");
            if (json) {
                jsonTree.create(json, $dom[0]);
            }
        }
    });
}

function createWebSocket(options) {
    options = options || {};
    var socket;
    if (location.host === 'demo.spiderflow.org') {
        socket = new WebSocket(options.url || 'ws://49.233.182.130:8088/ws');
    } else {
        socket = new WebSocket(options.url || (location.origin.replace("http", 'ws') + '/ws'));
    }
    socket.onopen = options.onopen;
    socket.onmessage = options.onmessage;
    socket.onerror = options.onerror || function () {
        layer.layer.msg('WebSocket错误');
    }
    return socket;
}

var flowId;

function Save() {
    validXML(function () {
        $.ajax({
            url: 'spider/save',
            type: 'post',
            data: {
                id: getQueryString('id') || flowId,
                xml: editor.getXML(),
                name: editor.graph.getModel().getRoot().data.get('spiderName') || '未定义名称',
            },
            success: function (id) {
                flowId = id;
                layui.layer.msg('保存成功', {
                    time: 800
                }, function () {
                    // location.href = "spiderList.html";
                })
            }
        })
    });
}

function allowDrop(ev) {
    ev.preventDefault();
}

function drag(ev) {
    ev.dataTransfer.setData("moverTarget", ev.target.id);
}

function drop(ev) {
    var moverTargetId = ev.dataTransfer.getData("moverTarget");
    $(ev.target).parents(".draggable").before($("#" + moverTargetId));
    ev.preventDefault();
    serializeForm();
}
